<template>
  <div class="app-container">
    <el-form
      :model="queryParams"
      ref="queryRef"
      :inline="true"
      v-show="showSearch"
      label-width="68px"
    >
      <el-form-item label="原始文件名" prop="originalName">
        <el-input
          v-model="queryParams.originalName"
          placeholder="请输入原始文件名"
          clearable
          @keyup.enter="handleQuery"
        />
      </el-form-item>
      <el-form-item label="逻辑删除 0正常 1删除" prop="isDelete">
        <el-input
          v-model="queryParams.isDelete"
          placeholder="请输入逻辑删除 0正常 1删除"
          clearable
          @keyup.enter="handleQuery"
        />
      </el-form-item>
      <el-form-item label="更新时间" prop="updatedTime">
        <el-date-picker
          clearable
          v-model="queryParams.updatedTime"
          type="date"
          value-format="YYYY-MM-DD"
          placeholder="请选择更新时间"
        >
        </el-date-picker>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="Search" @click="handleQuery"
          >搜索</el-button
        >
        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <!-- <el-button
          type="primary"
          plain
          icon="Plus"
          @click="handleAdd"
          v-hasPermi="['sbtz:file:add']"
          >新增</el-button
        > -->

        <el-button type="primary" plain icon="Plus" @click="openAddDialog">上传文件</el-button>
      </el-col>
      <el-col :span="1.5">
        <!-- <AttachmentsUploader
    ref="attRef"
    :entity-id="form.id"                
    :list-fn="listAttachments"
    :upload-fn="uploadAttachments"
    :delete-fn="delAttachments"
    accept=".png,.jpg,.jpeg,.webp,.gif,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar"
    :max-size-mb="100"
    list-type="picture-card"            
    :directory="true"
    :multiple="true"
    :show-table="true"
  />
  <fileUploader
    :entity-id="form.id"
    :list-fn="apiList"
    :upload-fn="apiUpload"
    :delete-fn="apiDelete"
    @uploaded="({count}) => $message.success(`已上传 ${count} 个文件`)"
    ref="attRef"
  /> -->

        <!-- <fileUpNoId
  :list-fn="listFile"
  :upload-fn="apiUpload"
  :delete-fn="apiDelete"
/> -->

        <!-- <fileUpNoId :upload-fn="apiUpload" @uploaded="onUploaded" /> -->
      </el-col>

      <el-col :span="1.5">
        <el-button
          type="success"
          plain
          icon="Edit"
          :disabled="single"
          @click="handleUpdate"
          v-hasPermi="['sbtz:file:edit']"
          >修改</el-button
        >
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="danger"
          plain
          icon="Delete"
          :disabled="multiple"
          @click="handleDelete"
          v-hasPermi="['sbtz:file:remove']"
          >删除</el-button
        >
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="warning"
          plain
          icon="Download"
          @click="handleExport"
          v-hasPermi="['sbtz:file:export']"
          >导出</el-button
        >
      </el-col>
      <right-toolbar
        v-model:showSearch="showSearch"
        @queryTable="getList"
      ></right-toolbar>
    </el-row>

    <el-table
      v-loading="loading"
      :data="fileList"
      @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column label="主键" align="center" prop="id" />
      <el-table-column label="原始文件名" align="center" prop="originalName" />
      <el-table-column
        label="服务器物理/相对存储路径"
        align="center"
        prop="storagePath"
      />
      <!-- 缩略图列（支持点击放大预览） -->
      <el-table-column label="预览/下载" min-width="180">
  <template #default="{ row }">
    <FilePreviewer :file="row" :base-api="baseApi" />
  </template>
</el-table-column>

 


      <el-table-column
        label="供前端访问的 URL"
        align="center"
        prop="storageUrl"
      />
      <el-table-column
        label="预览类型：图片/ PDF / 无"
        align="center"
        prop="previewType"
      />
      <el-table-column label="备注" align="center" prop="remark" />
      <el-table-column label="扩展信息(JSON)" align="center" prop="extraJson" />
      <el-table-column
        label="逻辑删除 0正常 1删除"
        align="center"
        prop="isDelete"
      />
      <el-table-column
        label="更新时间"
        align="center"
        prop="updatedTime"
        width="180"
      >
        <template #default="scope">
          <span>{{ parseTime(scope.row.updatedTime, "{y}-{m}-{d}") }}</span>
        </template>
      </el-table-column>
      <el-table-column
        label="操作"
        align="center"
        class-name="small-padding fixed-width"
      >
        <template #default="scope">
          <el-button link type="primary" @click="preview(scope.row)"
            >预览/下载</el-button
          >
          <el-button link type="danger" @click="removeOne(scope.row)"
            >删除</el-button
          >
          <el-button
            link
            type="primary"
            icon="Edit"
            @click="handleUpdate(scope.row)"
            v-hasPermi="['sbtz:file:edit']"
            >修改</el-button
          >
          <el-button
            link
            type="primary"
            icon="Delete"
            @click="handleDelete(scope.row)"
            v-hasPermi="['sbtz:file:remove']"
            >删除</el-button
          >
        </template>
      </el-table-column>
    </el-table>

    <pagination
      v-show="total > 0"
      :total="total"
      v-model:page="queryParams.pageNum"
      v-model:limit="queryParams.pageSize"
      @pagination="getList"
    />

    <AddAssetFilesDialog
    v-model="openAdd"
    v-model:bizTag="selectedType"
    :upload-fn="apiUploadWithField"
    :max-size-mb="500"
    :accept="ACCEPT_FILES"
    :type-options="typeOptions"
    @success="onAddDone" 
    @oversize="onOversize" 
  />


  <el-dialog
  v-model="pdfDialog.open"
  width="80%"
  top="5vh"
  :destroy-on-close="true"
  append-to-body
  title="PDF 预览"
>
  <iframe
    v-if="pdfDialog.url"
    :src="pdfDialog.url + '#toolbar=1&navpanes=0&scrollbar=1'"
    style="width:100%;height:80vh;border:none;"
  ></iframe>
  <template #footer>
    <el-button @click="download({ storageUrl: pdfDialog.url, originalName: '文件.pdf' })">下载</el-button>
    <el-button type="primary" @click="pdfDialog.open=false">关 闭</el-button>
  </template>
</el-dialog>

    <!-- 添加或修改文件管理对话框 -->
    <el-dialog :title="title" v-model="open" width="640px" append-to-body>
      <!-- 预览 + 更换 -->
      <el-card shadow="never" class="mb12">
        <template #header>
          <div
            style="
              display: flex;
              justify-content: space-between;
              align-items: center;
            "
          >
            <span>当前附件</span>
            <!-- 选择后立即替换 -->
            <el-upload
              :show-file-list="false"
              :auto-upload="false"
              :on-change="onReplaceChange"
              :accept="accept"
            >
              <el-button size="small" type="primary" :loading="replaceLoading"
                >更换文件</el-button
              >
            </el-upload>
          </div>
        </template>

        <div style="display: flex; gap: 16px; align-items: flex-start">
          <!-- 预览区域：图片就展示缩略图；其它提供打开按钮 -->
          <div class="preview-wrap">
            <div class="preview-box">
              <template
                v-if="isImage(form.previewType || form.mimeType || form.ext)"
              >
                <el-image
                  v-if="form.storageUrl"
                  :src="imgSrc"
                  :preview-src-list="[imgSrc]"
                  fit="contain"
                  style="width: 200px; height: 200px"
                  :z-index="3000"
                >
                  <template #error>
                    <div class="img-fallback">加载失败</div>
                  </template>
                </el-image>
                <div v-else class="img-fallback">暂无图片</div>
              </template>

              <template v-else>
                <el-button
                  v-if="form.storageUrl"
                  link
                  type="primary"
                  @click="preview(form)"
                  >打开当前文件</el-button
                >
                <div v-else class="img-fallback">暂无文件</div>
              </template>
            </div>

            <!-- 右侧信息保持你原来的 el-descriptions -->
            <el-descriptions :column="1" size="small" class="flex-1">
              <el-descriptions-item label="文件名">{{
                form.originalName || "-"
              }}</el-descriptions-item>
              <el-descriptions-item label="类型">{{
                form.mimeType || form.ext || "-"
              }}</el-descriptions-item>
              <el-descriptions-item label="大小(B)">{{
                form.sizeBytes ?? "-"
              }}</el-descriptions-item>
              <el-descriptions-item label="预览类型">{{
                form.previewType || "-"
              }}</el-descriptions-item>
              <el-descriptions-item label="URL">
                <el-link v-if="form.storageUrl" :href="imgSrc" target="_blank">
                  {{ form.storageUrl }}
                </el-link>
                <span v-else>-</span>
              </el-descriptions-item>
            </el-descriptions>
          </div>

          <!-- 简要信息 -->
        </div>
      </el-card>

      <!-- 原有表单：路径/URL 改为只读展示（避免手工改坏） -->
      <el-form ref="fileRef" :model="form" :rules="rules" label-width="120px">
        <!-- <el-form-item label="服务器路径" prop="storagePath">
          <el-input
            v-model="form.storagePath"
            type="textarea"
            :rows="2"
            readonly
          />
        </el-form-item> -->
        <el-form-item label="文件类型" prop="storageUrl">
          <el-select
          v-model="form.bizTag"
          placeholder="请选择文件类型"
          size="small"
          style="width: 180px"
          :disabled="uploading"
          clearable
        >
          <el-option
            v-for="opt in typeOptions"
            :key="opt.value"
            :label="opt.label"
            :value="opt.value"
          />
        </el-select>
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="form.remark" placeholder="备注（可选）" />
        </el-form-item>
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">保 存</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup name="File">
import {
  listFile,
  getFile,
  delFile,
  addFile,
  updateFile,
  apiUpload,
  apiUploadWithField,
  apiDelete,
  apiReplace,
} from "@/api/sbtz/file";
import AttachmentsUploader from "@/components/sbtz/file/AttachmentsUploader.vue";
import fileUploader from "@/components/sbtz/file/fileUploader.vue";
import fileUpNoId from "@/components/sbtz/file/fileUpNoId.vue";

import AddAssetFilesDialog from '@/components/sbtz/file/AddAssetFilesDialog.vue' 
import FilePreviewer from '@/components/sbtz/file/FilePreviewer.vue'
const openAdd = ref(false) 
const selectedType = ref('')

import { ElMessage, ElMessageBox } from "element-plus";
import { computed,reactive,watch } from "vue";

import {
  listAttachments,
  uploadAttachments,
  delAttachments,
} from "@/api/sbtz/attachment";
const attRef = ref(null);

const { proxy } = getCurrentInstance();

const ACCEPT_FILES =
  '.png,.jpg,.jpeg,.webp,.gif,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar,' +
  'application/zip,application/x-zip-compressed,application/x-rar-compressed,application/octet-stream'

const fileList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const typeOptions = reactive([
  { label: '通用', value: 'general' },
  { label: '图片', value: 'image' },
  { label: '文档', value: 'doc' },
  { label: '表格', value: 'sheet' },
  { label: '合同', value: 'contract' },
]); 

const data = reactive({
  form: {},
  queryParams: {
    pageNum: 1,
    pageSize: 10,
    originalName: null,
    storagePath: null,
    storageUrl: null,
    previewType: null,
    extraJson: null,
    isDelete: null,
    updatedTime: null,
  },
  rules: {
    originalName: [
      { required: true, message: "原始文件名不能为空", trigger: "blur" },
    ],
    ext: [{ required: true, message: "扩展名不能为空", trigger: "blur" }],
    mimeType: [
      { required: true, message: "MIME 类型不能为空", trigger: "change" },
    ],
    sizeBytes: [{ required: true, message: "大小不能为空", trigger: "blur" }],
    sha256: [
      { required: true, message: "内容 SHA256不能为空", trigger: "blur" },
    ],
    storagePath: [
      {
        required: true,
        message: "服务器物理/相对存储路径不能为空",
        trigger: "blur",
      },
    ],
    storageUrl: [
      { required: true, message: "供前端访问的 URL不能为空", trigger: "blur" },
    ],
    previewType: [
      {
        required: true,
        message: "预览类型：图片/ PDF / 无不能为空",
        trigger: "change",
      },
    ],
    bizTag: [{ required: true, message: "业务标签不能为空", trigger: "blur" }],
    createBy: [
      { required: true, message: "上传人姓名不能为空", trigger: "blur" },
    ],
    updateBy: [
      { required: true, message: "更新人姓名不能为空", trigger: "blur" },
    ],
    
    isDelete: [
      {
        required: true,
        message: "逻辑删除 0正常 1删除不能为空",
        trigger: "blur",
      },
    ],
    createTime: [
      { required: true, message: "创建时间不能为空", trigger: "blur" },
    ],
    updatedTime: [
      { required: true, message: "更新时间不能为空", trigger: "blur" },
    ],
  },
});

const { queryParams, form, rules } = toRefs(data);
const baseApi =
  (typeof import.meta !== 'undefined' && import.meta.env?.VITE_APP_BASE_API) ||
  (typeof process !== 'undefined' && process.env?.VUE_APP_BASE_API) || '';

// <FilePreviewer url="/profile/xxx.png" type="image" :base-api="baseApi" />

/** 查询文件管理列表 */
function getList() {
  loading.value = true;
  listFile(queryParams.value).then((response) => {
    fileList.value = response.rows;
    total.value = response.total;
    loading.value = false;
  });
}

function onOversize({ over, limitMB }) {
  // over 是超限的 File 列表
  const names = over.slice(0, 3).map(f => f.name).join('、') + (over.length > 3 ? ' 等' : '')
  ElMessage.warning(`有 ${over.length} 个文件超过 ${limitMB}MB：${names}（已跳过）`)
  console.warn('[oversize]', over.map(f => ({ name: f.name, size: f.size })))
}


// 取消按钮
function cancel() {
  open.value = false;
  reset();
}

function openAddDialog() {
  openAdd.value = true
}

// 上传成功后刷新列表
function onAddDone() {
  getList() // 复用你现有的方法
}

watch(openAdd, (val) => {
  if (!val) {
    selectedType.value = ''
  }
})

// 表单重置
function reset() {
  form.value = {
    id: null,
    originalName: null,
    ext: null,
    mimeType: null,
    sizeBytes: null,
    sha256: null,
    storagePath: null,
    storageUrl: null,
    previewType: null,
    imageWidth: null,
    imageHeight: null,
    pdfPages: null,
    bizTag: null,
    createBy: null,
    updateBy: null,
    remark: null,
    extraJson: null,
    isDelete: null,
    createTime: null,
    updatedTime: null,
  };
  proxy.resetForm("fileRef");
}

/** 搜索按钮操作 */
function handleQuery() {
  queryParams.value.pageNum = 1;
  getList();
}

function onUploaded({ count }) {
  ElMessage.success(`上传成功：${count} 个`);
  getList();
}

/** 生成可访问 URL（纯 JS 版） */
function makeAbsUrl(path) {
  if (!path) return "";
  if (/^(https?:)?\/\//i.test(path)) return path; // 已是完整URL

  const DEV_PREFIX =
    (import.meta?.env && import.meta.env.VITE_APP_BASE_API) ||
    (typeof process !== "undefined" &&
      process.env &&
      process.env.VUE_APP_BASE_API) ||
    ""; // 通常 /dev-api（开发）或 /prod-api（生产）

  // 开发环境需要前缀去走代理；生产多数情况可不加（见 C 节）
  if (DEV_PREFIX) {
    const left = String(DEV_PREFIX).replace(/\/+$/, "");
    const right = path.startsWith("/") ? path : "/" + path;
    return left + right;
  }
  // 没有前缀就直接返回相对路径（同域/Nginx直出时可用）
  return path.startsWith("/") ? path : "/" + path;
}

function preview(row) {
  const url = makeAbsUrl(row.storageUrl || row.fileUrl || row.url);
  if (!url) return;
  const a = document.createElement("a");
  a.href = encodeURI(url);
  a.target = "_blank";
  a.rel = "noopener noreferrer";
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}

// 接受文件类型限制（可复用你列表页上传同一份）
const accept =
  ".png,.jpg,.jpeg,.webp,.gif,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar";

// 替换 loading
const replaceLoading = ref(false);

// 判断是否图片预览
function isImage(typeOrExt) {
  const s = (typeOrExt || "").toString().trim().toLowerCase();
  if (!s) return false;
  // ✅ 兼容 previewType='image'
  if (s === "image") return true;
  // ✅ 兼容 mimeType='image/jpeg'
  if (s.startsWith("image/")) return true;
  // ✅ 兼容扩展名
  const ext = s.includes(".") ? s.split(".").pop() : s;
  return ["png", "jpg", "jpeg", "gif", "webp", "bmp", "svg"].includes(ext);
}

const imgSrc = computed(() => makeAbsUrl(form.value?.storageUrl || ""));


function downloadRow(url, name){
  // 你可以接管下载逻辑（比如带鉴权/代理下载），否则组件已自带兜底下载
  if(!url) return
  const a = document.createElement('a')
  a.href = url
  a.download = name || '下载文件'
  a.target = '_blank'
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}

// 选择新文件 -> 立即调用 replace 接口
async function onReplaceChange(uploadFile) {
  try {
    if (!form.value?.id) {
      ElMessage.warning("请选择要修改的记录");
      return;
    }
    const raw = uploadFile?.raw || uploadFile;
    if (!raw) return;

    // 可选：前端大小校验
    // if (raw.size > 100 * 1024 * 1024) { ElMessage.error('文件过大'); return }

    const fd = new FormData();
    fd.append("file", raw);
    // 如果你保留相对路径（文件夹），这里可 append relativePath
    // fd.append('relativePath', raw.webkitRelativePath || '')

    replaceLoading.value = true;
    await apiReplace(form.value.id, fd);

    // 刷新当前记录 & 表格
    await getFile(form.value.id).then((res) => {
      form.value = res.data || {};
    });
    await getList();

    ElMessage.success("已替换文件");
  } catch (e) {
    ElMessage.error("替换失败");
  } finally {
    replaceLoading.value = false;
  }
}

// 是否 PDF
function isPdf(typeOrExt) {
  const s = (typeOrExt || '').toString().trim().toLowerCase()
  if (!s) return false
  if (s === 'pdf') return true
  if (s === 'application/pdf') return true
  return s.endsWith('.pdf')
}

// 统一拿可访问 URL
function fileUrl(row) {
  return makeAbsUrl(row.storageUrl || row.fileUrl || row.url || '')
}

// 通用预览（非图片/PDF，尝试浏览器直接打开）
function previewPdf(row) {
  const url = fileUrl(row)
  if (!url) return
  // 图片/PDF在表格列里已经处理，这里统一兜底：新开标签
  window.open(encodeURI(url), '_blank', 'noopener,noreferrer')
}

// 下载（尽量触发浏览器下载；跨域需服务端返回 Content-Disposition）
function download(row) {
  const url = fileUrl(row)
  if (!url) return
  const a = document.createElement('a')
  a.href = url
  a.download = (row.originalName || row.fileName || '下载文件').toString()
  a.target = '_blank'
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}

// PDF 大窗预览
const pdfDialog = reactive({ open: false, url: '' })
function openPdf(row) {
  const url = fileUrl(row)
  if (!url) return
  pdfDialog.url = url
  pdfDialog.open = true
}

async function removeOne(row) {
  let ok = false;
  try {
    await ElMessageBox.confirm(
      `确定删除「${row.originalName || row.fileName || row.id}」吗？`,
      "提示",
      { type: "warning", confirmButtonText: "删除", cancelButtonText: "取消" }
    );
    ok = true;
  } catch {
    ok = false;
  }
  if (!ok) return;

  await apiDelete(row.id);
  ElMessage.success("已删除");
  await getList();
}

/** 重置按钮操作 */
function resetQuery() {
  proxy.resetForm("queryRef");
  handleQuery();
}

// 多选框选中数据
function handleSelectionChange(selection) {
  ids.value = selection.map((item) => item.id);
  single.value = selection.length != 1;
  multiple.value = !selection.length;
}

/** 新增按钮操作 */
function handleAdd() {
  reset();
  open.value = true;
  title.value = "添加文件管理";
}

/** 修改按钮操作 */
function handleUpdate(row) {
  reset();
  const _id = row.id || ids.value;
  getFile(_id).then((response) => {
    form.value = response.data;
    open.value = true;
    title.value = "修改文件管理";
  });
}

/** 提交按钮 */
function submitForm() {
  proxy.$refs["fileRef"].validate((valid) => {
    if (valid) {
      if (form.value.id != null) {
        console.log(form.value)
        updateFile(form.value).then((response) => {
          proxy.$modal.msgSuccess("修改成功");
          open.value = false;
          getList();
        });
      } else {
        addFile(form.value).then((response) => {
          proxy.$modal.msgSuccess("新增成功");
          open.value = false;
          getList();
        });
      }
    }
  });
}

/** 删除按钮操作 */
function handleDelete(row) {
  const _ids = row.id || ids.value;
  proxy.$modal
    .confirm('是否确认删除文件管理编号为"' + _ids + '"的数据项？')
    .then(function () {
      return delFile(_ids);
    })
    .then(() => {
      getList();
      proxy.$modal.msgSuccess("删除成功");
    })
    .catch(() => {});
}

/** 导出按钮操作 */
function handleExport() {
  proxy.download(
    "sbtz/file/export",
    {
      ...queryParams.value,
    },
    `file_${new Date().getTime()}.xlsx`
  );
}

getList();
</script>
<style scoped>
.preview-wrap {
  display: flex;
  gap: 16px;
  align-items: flex-start;
}
.preview-box {
  width: 220px;
  height: 140px;
  border: 1px dashed #e5e7eb;
  display: flex;
  align-items: center;
  justify-content: center;
}
.img-fallback {
  color: #909399;
  font-size: 12px;
}
 
.mb12{
  margin-bottom: 20px;
}

.thumb-img{
  width: 100px;
  height: 75px;          /* 4:3 小缩略图 */
  border-radius: 4px;
  overflow: hidden;
  cursor: zoom-in;
  box-shadow: 0 0 0 1px #eee inset;
}
.thumb-fallback{
  display: inline-flex;
  width: 100px;
  height: 75px;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: #909399;
  background: #fafafa;
  border-radius: 4px;
  box-shadow: 0 0 0 1px #eee inset;
}



/* 图片单元格：尽量展示完整图（等比缩放） */
.cell-image {
  width: 160px;
  height: 120px;
  background: #f5f7fa;
  border-radius: 6px;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
:deep(.cell-image .el-image__inner){
  width: 100%;
  height: 100%;
  object-fit: contain; /* 显示完整图片 */
}

.cell-muted{ color:#909399; font-size:12px; }

/* PDF 缩略容器 */
.pdf-thumb{
  width: 160px;
  height: 120px;
  position: relative;
  border: 1px solid #ebeef5;
  border-radius: 6px;
  overflow: hidden;
  background: #fafafa;
  cursor: pointer;
}
.pdf-thumb .pdf-mask{
  position:absolute; left:0; right:0; bottom:0;
  height: 22px; line-height:22px;
  text-align:center; font-size:12px;
  color:#fff; background: rgba(0,0,0,.35);
}

/* 你之前移动关闭按钮的样式仍可保留 */

</style>
